package org.example.model;


import javax.websocket.Session;
import java.io.IOException;
import java.util.Enumeration;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 保存websocket需要的信息
 * 所有客户端的session
 */

public class MessageCenter {

    //ConcurrentHashMap是线程安全结构，满足高并发（读并发写互斥）
    private static final ConcurrentHashMap<Integer, Session> clients = new ConcurrentHashMap<Integer, Session>();

    /*
    阻塞队列：存放消息，接收的客户端消息存放在里面
    再启动一个线程，去不停拉取队列中的消息并发送（接收和发送并发并行执行）
     */
    private static LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();

    private static volatile MessageCenter messageCenter;  //添加volatile禁止指令重排序

    private MessageCenter(){}

    public static MessageCenter getInstance(){
        //使用单例模式（懒汉模式），应用双重校验锁
        if(messageCenter == null){
            synchronized (MessageCenter.class){
                if(messageCenter == null){
                    messageCenter = new MessageCenter();
                    //使用lambda表达式
                    new Thread(()->{        //启动线程，从阻塞队列中取数据
                        while(true){
                            try{
                                String message = queue.take();;
                                sendMessage(message);
                            }catch(InterruptedException e){
                                e.printStackTrace();
                            }
                        }
                    }).start();   //启动线程
                }
            }
        }
        return messageCenter;
    }

    /*
    不直接发消息，先把客户端消息存放在阻塞队列中，由线程去执行发消息任务
     */
    public void addMessage(String message){
        queue.add(message);
    }



    //websocket建立连接时，添加用户id和客户端session，保存起来
    public static void addOnline(Integer userId, Session session){
        clients.put(userId, session);
    }

    //关闭websocket连接和出错时，删除客户端session
    public static void delOnline(Integer userId){
        clients.remove(userId);
    }

    /**
     * 接收到某客户端的消息，服务端将消息转发到所有客户端
     *
     * 存在问题 n个客户端都发送m条消息  服务端要转发n*m次消息
     * 每个接收的消息都是一个线程 都要等待websocket中onmessage方法执行完 这导致性能较差！
     */

    public static void sendMessage(String message){
        try{
            Enumeration<Session> e = clients.elements();   //遍历消息
            while(e.hasMoreElements()){
                Session session = e.nextElement();
                session.getBasicRemote().sendText(message);   //将文本消息展示到前端界面
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
